﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace UT3Bots.Communications
{
	internal class MessageEventArgs : EventArgs
	{
		private Message _message;
		
		#region Properties
		public Message Message
		{
			get { return this._message; }
		}
		#endregion

		public MessageEventArgs(Message Message)
		{
			this._message = Message;
		}
	}

	internal class MessageHandler
	{
		private UT3Connection _connection;
		private Queue<Message> _messageQueue;
        private Thread processThread;

		internal event EventHandler<MessageEventArgs> OnEventReceived;
        internal event EventHandler<TcpErrorEventArgs> OnErrorOccurred;


		#region Properties
		public UT3Connection Connection
		{
			get { return this._connection; }
		}
		public Queue<Message> MessageQueue
		{
			get { return this._messageQueue; }
		}
		#endregion

		//Constructor
		internal MessageHandler(string Server, int Port)
		{
			this._messageQueue = new Queue<Message>();
			this._connection = new UT3Connection(Server, Port);

			this._connection.OnDataReceived += new EventHandler<TcpDataEventArgs>(DataReceived);
			this._connection.OnErrorOccurred += new EventHandler<TcpErrorEventArgs>(ErrorOccurred);

            processThread = new Thread(new ThreadStart(ProcessQueue));
            processThread.Start();
		}

		internal void Disconnect()
		{
            processThread.Interrupt();
			this._connection.Disconnect();
		}
        
		private void ErrorOccurred(object sender, TcpErrorEventArgs e)
		{
			//this.Disconnect();
            if (OnErrorOccurred != null)
                OnErrorOccurred(sender, e);
		}

		private void DataReceived(object sender, TcpDataEventArgs e)
		{
			//List<Message> newMessages = Message.FromVisualizerData(System.Text.UTF8Encoding.UTF8.GetString(e.Data, 0, e.Data.Length));
            if (!String.IsNullOrEmpty(e.sData))
            {
                Message m = new Message(e.sData);
                lock (this._messageQueue)
                {

                    if (m.IsEvent && this.OnEventReceived != null)
                    {
                        OnEventReceived.Invoke(this, new MessageEventArgs(m));
                    }
                    else
                    {
                        this._messageQueue.Enqueue(m);
                        //Console.WriteLine("Added to queue. Waking up process thread.");
                        if(processThread.ThreadState == System.Threading.ThreadState.Suspended)
                            processThread.Resume();
                    }

                }
            }
		}

        private void ProcessQueue()
        {
            Console.WriteLine("Starting message queue processing thread.");
            while (processThread.IsAlive)
            {

                Message m = null; ;
                lock (MessageQueue)
                {
                    if (MessageQueue.Count > 0)
                    {
                        m = MessageQueue.Dequeue();
                    }
                }

                if (m != null && OnEventReceived != null)
                {
                    
                        // Console.WriteLine("Processing queue");
                        OnEventReceived(this, new MessageEventArgs(m));
                    
                }
                else
                {
                    //Console.WriteLine("Queue empty. Sleeping.");
                    processThread.Suspend();
                }

            }
            Console.WriteLine("Message queue processing thread ended.");
        }
	}
}
